package model

import (
	"fmt"
	"io"
	"strconv"
)

// Difficulty is Difficulty of a game
type Difficulty string

const (
	DifficultyEasy     Difficulty = "EASY"
	DifficultyMedium   Difficulty = "MEDIUM"
	DifficultyHard     Difficulty = "HARD"
	DifficultyVeryHard Difficulty = "VERY_HARD"
)

var AllDifficulty = []Difficulty{
	DifficultyEasy,
	DifficultyMedium,
	DifficultyHard,
	DifficultyVeryHard,
}

func (e Difficulty) IsValid() bool {
	switch e {
	case DifficultyEasy, DifficultyMedium, DifficultyHard, DifficultyVeryHard:
		return true
	}
	return false
}

func (e Difficulty) String() string {
	return string(e)
}

func (e *Difficulty) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = Difficulty(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid Difficulty", str)
	}
	return nil
}

func (e Difficulty) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type GameMode string

const (
	GameModeCoor   GameMode = "COOR"
	GameModeVersus GameMode = "VERSUS"
)

var AllGameMode = []GameMode{
	GameModeCoor,
	GameModeVersus,
}

func (e GameMode) IsValid() bool {
	switch e {
	case GameModeCoor, GameModeVersus:
		return true
	}
	return false
}

func (e GameMode) String() string {
	return string(e)
}

func (e *GameMode) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = GameMode(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid GameMode", str)
	}
	return nil
}

func (e GameMode) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type Rank string

const (
	RankGold   Rank = "GOLD"
	RankSiver  Rank = "SIVER"
	RankBronze Rank = "BRONZE"
)

var AllRank = []Rank{
	RankGold,
	RankSiver,
	RankBronze,
}

func (e Rank) IsValid() bool {
	switch e {
	case RankGold, RankSiver, RankBronze:
		return true
	}
	return false
}

func (e Rank) String() string {
	return string(e)
}

func (e *Rank) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = Rank(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid Rank", str)
	}
	return nil
}

func (e Rank) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type Status string

const (
	StatusOffline   Status = "OFFLINE"
	StatusWandering Status = "WANDERING"
	StatusWaiting   Status = "WAITING"
	StatusReady     Status = "READY"
	StatusGaming    Status = "GAMING"
)

var AllStatus = []Status{
	StatusOffline,
	StatusWandering,
	StatusWaiting,
	StatusReady,
	StatusGaming,
}

func (e Status) IsValid() bool {
	switch e {
	case StatusOffline, StatusWandering, StatusWaiting, StatusReady, StatusGaming:
		return true
	}
	return false
}

func (e Status) String() string {
	return string(e)
}

func (e *Status) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = Status(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid Status", str)
	}
	return nil
}

func (e Status) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type RoomStatus string

const (
	RoomStatusWaiting RoomStatus = "WAITING"
	RoomStatusGaming  RoomStatus = "GAMING"
)

var AllRoomStatus = []RoomStatus{
	RoomStatusWaiting,
	RoomStatusGaming,
}

func (e RoomStatus) IsValid() bool {
	switch e {
	case RoomStatusWaiting, RoomStatusGaming:
		return true
	}
	return false
}

func (e RoomStatus) String() string {
	return string(e)
}

func (e *RoomStatus) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = RoomStatus(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid RoomStatus", str)
	}
	return nil
}

func (e RoomStatus) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}
